package com.daykw.wkinfo.http;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.net.Authenticator;
import java.net.PasswordAuthentication;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.zip.GZIPInputStream;

import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.commons.httpclient.params.HttpClientParams;
import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.ParseException;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.CharArrayBuffer;
import org.apache.log4j.Logger;
import org.nutz.dao.entity.Record;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.remote.DesiredCapabilities;

import com.daykw.wkinfo.utils.IPPoolMap;

public class HttpBase {

	private static Logger logger = Logger.getLogger(HttpBase.class);
	private static final java.util.Random RANDOM = new java.util.Random();
	public static String FIREFOX_PATH = System.getProperty("user.dir") + File.separator + "Mozilla Firefox"
			+ File.separator + "firefox.exe";

	protected static DesiredCapabilities fCaps;
	static {

		System.setProperty("webdriver.firefox.bin", FIREFOX_PATH);

	}

	public WebDriver getFirefox() throws IOException {

		// Prepare capabilities
		fCaps = new DesiredCapabilities();
		fCaps.setJavascriptEnabled(true);
		fCaps.setCapability("takesScreenshot", false);

		WebDriver fDriver = new FirefoxDriver(fCaps);

		return fDriver;
	}

	/**
	 * Post请求
	 * 
	 * @return
	 * @throws Exception
	 */
	public String post(String url, String charset, Map<String, String> header, String data, boolean isproxy)
			throws Exception {
		CustomPostMethod postMethod = new CustomPostMethod(url);
		String ip = null;
		SimpleDateFormat ft = new SimpleDateFormat("yyyyMMddHHmmss");
		try {
			HttpClient client = getClient(charset);
//			postMethod.setRequestHeader("User-Agent",
//					"Mozilla/5.0 (Windows NT " + (RANDOM.nextInt(5) + 1) + ".1) AppleWebKit/"
//							+ (RANDOM.nextInt(537) + 1) + "." + (RANDOM.nextInt(11) + 1)
//							+ " (KHTML, like Gecko) Chrome/" + (RANDOM.nextInt(23) + 1) + ".0."
//							+ (RANDOM.nextInt(1271) + 1) + "." + (RANDOM.nextInt(95) + 1) + " Safari/"
//							+ (RANDOM.nextInt(537) + 1) + "." + (RANDOM.nextInt(11) + 1) + "");
//			postMethod.setRequestHeader("Accept-Encoding", "gzip,deflate,sdch");
			Set<String> headers = header.keySet();
			for (String key : headers) {
				postMethod.setRequestHeader(key, header.get(key));
			}
			if (isproxy) {

				Record ips = IPPoolMap.getLqueue().take();

				Calendar beforeTime = Calendar.getInstance();
				beforeTime.add(Calendar.MINUTE, -4);// 5分钟之前的时间
				ip = ips.getString("ips");
				String date = ips.getString("time");
				Date be = beforeTime.getTime();
				Date iptime = ft.parse(date);
				while (ips != null && be.after(iptime)) {
					IPPoolMap.removeIp(ip);
					ips = IPPoolMap.getLqueue().take();
					ip = ips.getString("ips");
					date = ips.getString("time");
					iptime = ft.parse(date);

				}

				String host = ip.split(":")[0];
				Integer port = Integer.parseInt(ip.split(":")[1]);

				client.getHostConfiguration().setProxy(host, port);

			}
			postMethod.setRequestEntity(new StringRequestEntity(data, "text/html", "UTF-8"));

			int statusCode = client.executeMethod(postMethod);// 回车——出拳！
			if (statusCode == 200) {
				String result = postMethod.getResponseBodyAsString();

				return result;
			}
			postMethod.abort();
			throw new java.net.ConnectException("请求错误,status code is[" + statusCode + "]");
		} catch (java.net.ConnectException e) {
			if (ip != null) {
				IPPoolMap.removeIp(ip);
				return "fail";
			} else {
				throw e;
			}

		} catch (java.net.SocketTimeoutException e) {
			if (ip != null) {
				IPPoolMap.removeIp(ip);
				return "fail";
			} else {
				throw e;
			}
		} catch (java.net.SocketException e) {
			if (ip != null) {
				IPPoolMap.removeIp(ip);
				return "fail";
			} else {
				throw e;
			}
		} catch (org.apache.commons.httpclient.ConnectTimeoutException e) {
			if (ip != null) {
				IPPoolMap.removeIp(ip);
				return "fail";
			} else {
				throw e;
			}
		} catch (javax.net.ssl.SSLHandshakeException e) {
			if (ip != null) {
				IPPoolMap.removeIp(ip);
				return "fail";
			} else {
				throw e;
			}
		} catch (Exception e) {
			if (ip != null) {
				IPPoolMap.removeIp(ip);
				return "fail";
			} else {
				throw e;
			}
		} finally {
			postMethod.releaseConnection();
		}

	}
	public String get(String url, String charset, Map<String, String> header, boolean isproxy) throws Exception {
		CustomGetMethod getMethod = new CustomGetMethod(url);
		String ip = null;
		SimpleDateFormat ft = new SimpleDateFormat("yyyyMMddHHmmss");
		try {
			HttpClient client = getClient(charset);

			if (isproxy) {

				Record ips = IPPoolMap.getLqueue().take();

				Calendar beforeTime = Calendar.getInstance();
				beforeTime.add(Calendar.MINUTE, -4);// 5分钟之前的时间
				 ip = ips.getString("ips");
				String date = ips.getString("time");
				Date be = beforeTime.getTime();
				Date iptime = ft.parse(date);
				while (ips != null && be.after(iptime)) {
					IPPoolMap.removeIp(ip);
					ips = IPPoolMap.getLqueue().take();
					ip = ips.getString("ips");
					date = ips.getString("time");
					iptime = ft.parse(date);

				}

				String host = ip.split(":")[0];
				Integer port = Integer.parseInt(ip.split(":")[1]);

				client.getHostConfiguration().setProxy(host, port);

			}
	

			

			if (header != null && !header.isEmpty()) {
				Set<String> keys = header.keySet();
				for (String key : keys) {
					getMethod.setRequestHeader(key, header.get(key));
				}
			}

			int statusCode = client.executeMethod(getMethod);// 回车——出拳！
			if (statusCode == 200) {
				// getResponseBodyAsString
				String result = getMethod.getResponseBodyAsString();
				
				return result;
			} else {
				if (statusCode == 404) {
					return "404";
				} else {
					IPPoolMap.removeIp(ip);
					return "fail";
				}

			}

		} catch (java.net.ConnectException e) {
			if (ip != null) {
				IPPoolMap.removeIp(ip);
				return "fail";
			} else {
				throw e;
			}

		} catch (java.net.SocketTimeoutException e) {
			if (ip != null) {
				IPPoolMap.removeIp(ip);
				return "fail";
			} else {
				throw e;
			}
		} catch (java.net.SocketException e) {
			if (ip != null) {
				IPPoolMap.removeIp(ip);
				return "fail";
			} else {
				throw e;
			}
		} catch (org.apache.commons.httpclient.ConnectTimeoutException e) {
			if (ip != null) {
				IPPoolMap.removeIp(ip);
				return "fail";
			} else {
				throw e;
			}
		} catch (javax.net.ssl.SSLHandshakeException e) {
			if (ip != null) {
				IPPoolMap.removeIp(ip);
				return "fail";
			} else {
				throw e;
			}
		} catch (Exception e) {
			IPPoolMap.removeIp(ip);
			return "fail";

		} finally {
			getMethod.abort();

			getMethod.releaseConnection();
		}

	}
	public synchronized Response httpGet(String url, Map<String, String> headers) throws Exception {
		HttpClient client = getClient("utf-8");
		CustomGetMethod getMethod = new CustomGetMethod(url);// 创建一个get方法，类似在浏览器地址栏中输入一个地址
		if (headers != null) {
			Set<String> keys = headers.keySet();
			for (String k : keys) {
				getMethod.setRequestHeader(k, headers.get(k));
			}
		}
		getMethod.setRequestHeader("accept",
				"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
		getMethod.setRequestHeader("Accept-Encoding", "gzip, deflate, sdch");
		getMethod.setRequestHeader("Accept-Language", "zh-CN,zh;q=0.8");
		getMethod.setRequestHeader("Upgrade-Insecure-Requests", "1");
		getMethod.setRequestHeader("User-Agent",
				"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36");

		int statusCode = client.executeMethod(getMethod);// 回车——出拳！

		Header[] _map = getMethod.getResponseHeaders();
		Map<String, String> map = new HashMap<String, String>();
		for (Header h : _map) {
			map.put(h.getName(), h.getValue());
		}
		if (statusCode == 200) {
			String body = getMethod.getResponseBodyAsString();
			getMethod.releaseConnection();
			Response r = new Response();
			r.setResult(body);
			r.setHeader(map);
			r.setStatus(statusCode);
			getMethod.abort();
			getMethod.releaseConnection();// 释放，记得收拳哦
			return r;
		}
		if (statusCode == 500) {
			String body = getMethod.getResponseBodyAsString();
			getMethod.releaseConnection();
			if (StringUtils.isNotEmpty(body)) {
				Response r = new Response();
				r.setResult(body);
				r.setHeader(map);
				r.setStatus(statusCode);
				getMethod.abort();
				getMethod.releaseConnection();// 释放，记得收拳哦
				return r;
			}
			getMethod.abort();
			getMethod.releaseConnection();// 释放，记得收拳哦
			throw new java.net.ConnectException("请求错误,status code is[" + statusCode + "]");
		}
		String body = getMethod.getResponseBodyAsString();
		Response r = new Response();
		r.setResult(body);
		r.setHeader(map);
		r.setStatus(statusCode);
		getMethod.abort();
		getMethod.releaseConnection();// 释放，记得收拳哦
		return r;
	}

	public synchronized String get(String url, Map<String, String> headers) throws Exception {
		HttpClient client = getClient("utf-8");
		CustomGetMethod getMethod = new CustomGetMethod(url);// 创建一个get方法，类似在浏览器地址栏中输入一个地址
		if (headers != null) {
			Set<String> keys = headers.keySet();
			for (String k : keys) {
				getMethod.setRequestHeader(k, headers.get(k));
			}
		}
		getMethod.setRequestHeader("accept",
				"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
		getMethod.setRequestHeader("Accept-Encoding", "gzip, deflate, sdch");
		getMethod.setRequestHeader("Accept-Language", "zh-CN,zh;q=0.8");
		getMethod.setRequestHeader("Upgrade-Insecure-Requests", "1");
		getMethod.setRequestHeader("User-Agent",
				"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36");

		int statusCode = client.executeMethod(getMethod);// 回车——出拳！

		Header[] _map = getMethod.getResponseHeaders();
		Map<String, String> map = new HashMap<String, String>();
		for (Header h : _map) {
			map.put(h.getName(), h.getValue());
		}
		if (statusCode == 200) {
			String body = getMethod.getResponseBodyAsString();
			getMethod.releaseConnection();

			getMethod.abort();
			getMethod.releaseConnection();// 释放，记得收拳哦
			return body;
		}
		if (statusCode == 500) {
			String body = getMethod.getResponseBodyAsString();
			getMethod.releaseConnection();
			if (StringUtils.isNotEmpty(body)) {

				getMethod.abort();
				getMethod.releaseConnection();// 释放，记得收拳哦
				return body;
			}
			getMethod.abort();
			getMethod.releaseConnection();// 释放，记得收拳哦
			throw new java.net.ConnectException("请求错误,status code is[" + statusCode + "]");
		}
		String body = getMethod.getResponseBodyAsString();

		getMethod.abort();
		getMethod.releaseConnection();// 释放，记得收拳哦
		return body;
	}

	private HttpClient getClient(String charset) {
		MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
		Integer MAX_TIME_OUT = 5000;
		// Integer MAX_IDLE_TIME_OUT = 60000;
		Integer MAX_CONN = 5000;
		connectionManager.closeIdleConnections(MAX_TIME_OUT);
		connectionManager.getParams().setParameter("http.connection-manager.max-total", MAX_CONN);
		HttpClient client = new HttpClient(connectionManager);
		HttpConnectionManagerParams params = client.getHttpConnectionManager().getParams();
		params.setConnectionTimeout(5000);
		params.setSoTimeout(5000);
		params.setDefaultMaxConnectionsPerHost(500);
		params.setMaxTotalConnections(1500);
		params.setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler());

		HttpClientParams hcp = client.getParams();
		// hcp.setParameter("http.connection.timeout", 5 * 1000);
		// hcp.setParameter("http.connection-manager.timeout", 5 * 1000);
		hcp.setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, charset);
		hcp.setAuthenticationPreemptive(true);
		return client;
	}

	public String getResponseBodyAsString(GetMethod getMethod) throws IOException {

		GZIPInputStream gzin;

		if (getMethod.getResponseBody() != null || getMethod.getResponseBodyAsStream() != null) {

			if (getMethod.getResponseHeader("Content-Encoding") != null

					&& getMethod.getResponseHeader("Content-Encoding").getValue().toLowerCase().indexOf("gzip") > -1) {

				// For GZip response

				InputStream is = getMethod.getResponseBodyAsStream();

				gzin = new GZIPInputStream(is);

				InputStreamReader isr = new InputStreamReader(gzin, getMethod.getResponseCharSet());

				java.io.BufferedReader br = new java.io.BufferedReader(isr);

				StringBuffer sb = new StringBuffer();

				String tempbf;

				while ((tempbf = br.readLine()) != null) {
					sb.append(tempbf);
					sb.append("\r\n");
				}
				isr.close();
				gzin.close();
				return sb.toString();
			} else {
				// For deflate response
				return getMethod.getResponseBodyAsString();
			}
		} else {
			return null;
		}

	}

	public String enCodetoString(final HttpEntity entity, final String defaultCharset)
			throws IOException, ParseException {
		return enCodetoStringDo(entity, defaultCharset != null ? Charset.forName(defaultCharset) : null);
	}

	public String enCodetoStringDo(final HttpEntity entity, Charset defaultCharset) throws IOException, ParseException {
		if (entity == null) {
			throw new IllegalArgumentException("HTTP entity may not be null");
		}
		InputStream instream = entity.getContent();
		if (instream == null) {
			return null;
		}
		try {
			if (entity.getContentLength() > Integer.MAX_VALUE) {
				throw new IllegalArgumentException("HTTP entity too large to be buffered in memory");
			}
			int i = (int) entity.getContentLength();
			if (i < 0) {
				i = 4096;
			}
			Charset charset = null;
			try {
				// ContentType contentType = ContentType.get(entity);
				// if (contentType != null) {
				// charset = contentType.getCharset();
				// }
			} catch (final UnsupportedCharsetException ex) {
				throw new UnsupportedEncodingException(ex.getMessage());
			}
			if (charset == null) {
				charset = defaultCharset;
			}
			if (charset == null) {
				charset = HTTP.DEF_CONTENT_CHARSET;
			}
			Reader reader = new InputStreamReader(instream, charset);
			CharArrayBuffer buffer = new CharArrayBuffer(i);
			char[] tmp = new char[1024];
			int l;
			while ((l = reader.read(tmp)) != -1) {
				buffer.append(tmp, 0, l);
			}
			return buffer.toString();
		} finally {
			instream.close();
		}
	}

	public synchronized String http(String url, Map<String, String> headers) throws Exception {
		URL u = new URL(url);
		// 创建HttpsURLConnection对象，并设置其SSLSocketFactory对象
		URLConnection.setDefaultAllowUserInteraction(true);
		URLConnection httpsConn = u.openConnection();

		Set<String> keys = headers.keySet();
		for (String k : keys) {
			httpsConn.setRequestProperty(k, headers.get(k));
		}

		// 取得该连接的输入流，以读取响应内容
		BufferedReader insr = new BufferedReader(new InputStreamReader(httpsConn.getInputStream()));

		// 读取服务器的响应内容并显示
		StringBuffer sb = new StringBuffer();
		String s;
		while ((s = insr.readLine()) != null) {
			sb.append(s + "\n");
		}
		return sb.toString();
	}

	public static void main(String[] args) {
		try {
			// WebDriverPool wp = new WebDriverPool();
			Map<String, String> headers = new HashMap<String, String>();
			headers.put("Accept", "application/json, text/plain, */*");
			headers.put("Accept-Encoding", "gzip, deflate");
			headers.put("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8");
			headers.put("Appversion", "1.0.0");
			headers.put("Cache-Control", "no-cache");
			headers.put("Content-Type", "application/json;charset=UTF-8");
			headers.put("Cookie",
					"connect.sid=s%3Akn4CmnMi5iw3RMkw3dYUyeM7H6AFG5yQ.uJvCntOyQY21EljSW6fhfPCjd9zUvR%2Fjh94YJiiKArw; CNZZDATA1261306096=466933065-1533706210-%7C1533706210; Hm_lvt_fecce484974a74c6d10f421b6d3bd395=1533711446; TY_SESSION_ID=d7cb03bf-287a-4f30-965b-1ff094d88c86; CCKF_visitor_id_100847=1112568797; cckf_track_100847_AutoInviteNumber=0; cckf_track_100847_ManualInviteNumber=0; userConfig=%7B%22moduleList%22%3A%5B%5D%2C%22userStaffType%22%3A0%2C%22isIpUser%22%3A0%2C%22parentId%22%3A0%2C%22sourceSiteUrl%22%3Anull%2C%22sourceSiteName%22%3Anull%2C%22clientSource%22%3A%22alphalawyerkhly%22%2C%22trial%22%3Afalse%7D; autologin=true; loginId=324515bcd68643e2a1a98fe0b47a2688; userInfo=%7B%22id%22%3A%22%22%2C%22username%22%3A%22alphalawyer%22%2C%22password%22%3A%220x010000009dd5c00b47dfb10ab0eb31ef7d2b13bbb43e5813bcb926b91924746549f17ae3b602fa49a4cb30a6%22%2C%22email%22%3A%22alphalawyer%40fsoo.com%22%2C%22userLang%22%3A%22cn%22%2C%22userPageSize%22%3A100%2C%22isSend%22%3Atrue%2C%22sendLang%22%3A%22cn%22%2C%22recieveEmails%22%3A%5B%5D%2C%22userType%22%3A%22normal%22%2C%22groupName%22%3A%22law%22%2C%22libraryCode%22%3A%22%22%2C%22licences%22%3A400%2C%22telephone%22%3A%221000070349%22%2C%22conf%22%3A%22%7B%5C%22legislationViewType%5C%22%3A%5C%22group%5C%22%2C%5C%22lawExpressViewType%5C%22%3A%5C%22group%5C%22%2C%5C%22mLegislationViewType%5C%22%3A%5C%22list%5C%22%2C%5C%22mLawExpressViewType%5C%22%3A%5C%22list%5C%22%7D%22%7D; check=valid; Hm_lpvt_fecce484974a74c6d10f421b6d3bd395=1533711475; cckf_track_100847_LastActiveTime=1533711475");
			headers.put("Host", "law.wkinfo.com.cn.");
			headers.put("Identification", "_4ea3ef209ad811e8ab2a890a59517782");
			headers.put("Origin", "http://law.wkinfo.com.cn.");
			headers.put("Referer", "https://law.wkinfo.com.cn/legislation/list?mode=advanced");
			headers.put("User-Agent",
					"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36");
			headers.put("X-Tingyun-Id", "tN6Win9ZeY4;r=11995442");

			HttpBase http = new HttpBase();
			for (int i = 39; i <= 825; i++) {
				try {
					int page = i * 100;
					String url = "http://law.wkinfo.com.cn./csi/search";
					String json = "{\"indexId\":\"law.legislation\",\"query\":{\"queryString\":\"topicClassification:((53))\",\"filterQueries\":[],\"filterDates\":[\"promulgatingDate:[1990.01.01 TO 2018.08.31]\"]},\"searchScope\":{\"treeNodeIds\":[]},\"relatedIndexQueries\":[],\"sortOrderList\":[{\"sortKey\":\"important\",\"sortDirection\":\"ASC\"},{\"sortKey\":\"promulgatingDate\",\"sortDirection\":\"DESC\"}],\"pageInfo\":{\"limit\":6,\"offset\":0},\"otherOptions\":{\"requireLanguage\":\"cn\",\"relatedIndexEnabled\":false,\"groupEnabled\":true,\"smartEnabled\":true,\"buy\":false,\"summaryLengthLimit\":100,\"advanced\":true,\"synonymEnabled\":true,\"isHideBigLib\":0},\"chargingInfo\":{\"useBalance\":true}}";
					// String
					// json="{\"indexId\":\"law.legislation\",\"query\":{\"queryString\":\"*:*\",\"filterQueries\":[\"defaultRangeDoc:1\"],\"filterDates\":[]},\"searchScope\":{\"treeNodeIds\":[\"promulgatingDateǁ[2017.08.07
					// TO
					// 2018.08.07]ǁǂ\",\"levelEffectǁ005ǁǂ\"]},\"relatedIndexQueries\":[],\"sortOrderList\":[{\"sortKey\":\"important\",\"sortDirection\":\"ASC\"},{\"sortKey\":\"promulgatingDate\",\"sortDirection\":\"DESC\"}],\"pageInfo\":{\"limit\":100,\"offset\":"+page+"},\"otherOptions\":{\"requireLanguage\":\"cn\",\"relatedIndexEnabled\":true,\"groupEnabled\":false,\"smartEnabled\":true,\"buy\":false,\"summaryLengthLimit\":100,\"advanced\":false,\"synonymEnabled\":true,\"isHideBigLib\":0},\"chargingInfo\":{\"useBalance\":true}}";
					String html = http.post(url, "utf-8", headers, json, false);

					System.out.println(html);
				} catch (Exception e) {
					i--;
				}
			}

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

class ProxyAuthenticator extends Authenticator {
	private String user, password;

	public ProxyAuthenticator(String user, String password) {
		this.user = user;
		this.password = password;
	}

	protected PasswordAuthentication getPasswordAuthentication() {
		return new PasswordAuthentication(user, password.toCharArray());
	}

}
